package cn.ilovese.collect.controller.socket;

import cn.ilovese.collect.service.user.MessageService;
import cn.ilovese.collect.serviceimpl.user.MessageServiceImpl;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * websocket服务器端点
 * @ServerEndpoint 类级别注解，将当前类定义为一个websocket服务端节点，value表示访问路径
 */
@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class WebSocketServer {
    private static MessageService messageService=new MessageServiceImpl();
    private static Logger logger = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 与客户端的连接会话，服务器端通过它向客户端发送消息
     */
    private Session session;
    private Integer sessionId;
    /**
     * 使用concurrent包的线程安全set，用来存放每个客户端对应的WebSocketServer对象
     */
    private static CopyOnWriteArraySet<WebSocketServer> websocketSet = new CopyOnWriteArraySet();

    /**
     * 静态变量记录在线连接数，应该把它设计成线程安全的
     */
    private static AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 新的连接建立成功后调用此方法，此方法严禁加入死循环或线程堵塞，会导致其他事件监听失效
     *
     * @param session
     * @param userId
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        // session超时时间，超时后无法再发送消息，服务端几秒之后会触发onClose时间
        session.setMaxIdleTimeout(60 * 1000 * 30);
        // 获取当前session
        this.session = session;
        this.sessionId= Integer.valueOf(userId);
        // 将当前session加入到set中
        websocketSet.add(this);
        // 在线用户连接数+1
        addOnlineCount();
        logger.info("当前用户连接数onlineCount = {}", getOnlineCount());
        /*int nums=messageService.getMessageNums(Integer.valueOf(userId));
        try {
            Map<String, Object> maps = new HashMap<>();
            maps.put("type", "sendMessage");
            maps.put("data",String.valueOf(nums));
            this.session.getBasicRemote().sendText((JSON.toJSONString(maps)));
        } catch (IOException e) {
            logger.error("服务端初始化用户{}异常，异常信息为：{}",Integer.valueOf(userId), e.getMessage());
        }*/
    }

    /**
     * 服务器端收到客户端消息时调用此方法发
     *
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        logger.info("当前发送人sessionId = {}， 发送内容为：{}", sessionId, message);
        Map<String, Object> maps = new HashMap<>();
        maps.put("type", message);
        this.sendMessage(maps);
    }

    /**
     * 断开连接时调用此方法
     */
    @OnClose
    public void onClose() {
        // 删除当前用户session
        websocketSet.remove(this);
        // 在线用户连接数-1
        subOnlineCount();
        try {
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 出现错误时调用此方法
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        logger.info("发生错误：{}， sessionId = {}", error.getMessage(), session.getId());
        error.printStackTrace();
    }

    /**
     * 客户端单发消息
     *
     * @param obj
     * @throws IOException
     */
    public void sendMessage(Object obj) {
        try {
            synchronized (this.session) {
                this.session.getBasicRemote().sendText((JSON.toJSONString(obj)));
            }
        } catch (IOException e) {
            logger.error("客户端发消息异常，异常信息为：{}", e.getMessage());
        }
    }
    /**
     * 服务器发消息给特定用户
     *
     * @param nums:未读消息数量
     */
    public static void sendMessageToSpecificUser(Integer nums,Integer uid) {
        for (WebSocketServer webSocketServer : websocketSet) {
            if(webSocketServer.getSessionId()==uid) {
                try {
                    Map<String, Object> maps = new HashMap<>();
                    maps.put("type", "sendMessage");
                    maps.put("data",String.valueOf(nums));
                    synchronized (webSocketServer.session) {
                        webSocketServer.session.getBasicRemote().sendText((JSON.toJSONString(maps)));
                    }
                } catch (IOException e) {
                    logger.error("服务端发送消息给用户{}异常，异常信息为：{}",uid, e.getMessage());
                }
            }
        }
    }
    /**
     * 服务器群发消息给客户端
     *
     * @param message
     */
    public void sendMessageToAll(String message) {
        for (WebSocketServer webSocketServer : websocketSet) {
            try {
                webSocketServer.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                logger.error("服务端群发消息异常，异常信息为：{}", e.getMessage());
            }
        }
    }

    /**
     * 获取当前用户连接数
     *
     * @return
     */
    public static synchronized Integer getOnlineCount() {
        return WebSocketServer.onlineCount.get();
    }

    /**
     * 当前在线用户连接数+1
     */
    private static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount.addAndGet(1);
    }

    /**
     * 当前在线用户连接数-1
     */
    private static synchronized void subOnlineCount() {
        if (WebSocketServer.onlineCount.get() > 0) {
            WebSocketServer.onlineCount.addAndGet(-1);
        }
    }

    public Integer getSessionId() {
        return sessionId;
    }
}
